﻿// Ok this is our implementation of The Directive Manager...

// NVelocity doesn't like being in the GAC so we have to jump through hoops to get it so....
// If a new version EVER gets compiled delete this.
namespace Collaboris.Saf.Actions.Templating
{
    using System;
    using System.Collections;

    using global::NVelocity.App;
    using global::NVelocity.Runtime.Directive;

    public class DirectiveManager : IDirectiveManager
    {
        private IDictionary name2Type = Hashtable.Synchronized(new Hashtable());

        public DirectiveManager()
        {
        }

        public virtual void Register(String directiveTypeName)
        {
            directiveTypeName = directiveTypeName.Replace(';', ',');

            if (directiveTypeName.ToLower().Contains("nvelocity") && 
                ! directiveTypeName.ToLower().Contains("publickeytoken"))
            {
                directiveTypeName = directiveTypeName
                                    + ", Version=1.0.3.0, Culture=neutral, PublicKeyToken=407dd0808d44fbdc";
            }

            Type type = Type.GetType(directiveTypeName, false, false);

            if (type == null)
            {
                throw new Exception("Could not resolve type " + directiveTypeName);
            }

            Directive directive = (Directive)Activator.CreateInstance(type);

            this.name2Type[directive.Name] = type;
        }

        public virtual Directive Create(String name, Stack directiveStack)
        {
            Type type = (Type)this.name2Type[name];

            if (type != null)
            {
                return (Directive)Activator.CreateInstance(type);
            }
            else if (directiveStack.Count != 0)
            {
                Directive parent = (Directive)directiveStack.Peek();

                if (parent.SupportsNestedDirective(name))
                {
                    return parent.CreateNestedDirective(name);
                }
            }

            return null;
        }

        public virtual bool Contains(String name)
        {
            return this.name2Type.Contains(name);
        }
    }
}